/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

#include <cstring>
#include <iostream>
#include <string>
#include <map>
#include <curl/curl.h>
#include "utils.h"
#include "BaseRequest.h"
#include "ApiBase.h"

using std::string;
using std::map;

namespace AliYunCore{
	/**
	 *	get the reponse of aliyun according the request
	 */
	string ApiBase::getResponse(BaseRequest &request){
		request.Domain = this->getServiceDomain(request.RegionId, request.ProductName);
		string api = request.Protocol+"://"+request.Domain;
		map<string,string> queryData;//query parameter container
		map<string,string> bodyData;//body parameter container
		string::size_type startpos = 0;
		string target;
		for(map<string,string>::const_iterator iter=request.KVMap.begin();iter!=request.KVMap.end();iter++){
			//ignore parameters that value is empty
			if( iter->second != "" ){
				if( request.KPMap[iter->first]=="Query" ){
					//collect data that store in the query part of url
					queryData[iter->first] = iter->second;
				} else if( request.KPMap[iter->first]=="Body" ){
					//collect data that store in the body(http post)
					bodyData[iter->first] = iter->second;
				} else if( request.KPMap[iter->first]=="Path" ){
					//fill the parameters in the path of the url
					startpos = 0;
					target = "[" + iter->first + "]";
					while (startpos!= string::npos) {
						startpos = request.Path.find(target);
						if( startpos != string::npos ) {
							request.Path.replace(startpos , target.length() , iter->second);
						}
					}
				} else if( request.KPMap[iter->first]=="Domain" ){
					//TODO
				} else if( request.KPMap[iter->first]=="Header" ){
					//TODO
				}
			}
		}
		api += request.Path;
		api += "/?";

		EncodeParamValue(bodyData);
		string postFields = MakeQueryStr(bodyData);

		queryData["RegionId"] = request.RegionId;
		queryData["Action"] = request.Action;
		queryData["Format"] = request.Format;
		queryData["Version"] = request.Version;
		queryData["AccessKeyId"] = request.AccessKeyId;
		queryData["SignatureMethod"] = request.SignatureMethod;
		queryData["SignatureNonce"] = MakeRand();
		queryData["SignatureVersion"] = request.SignatureVersion;
		queryData["Timestamp"] = UTCTime();

		EncodeParamValue(queryData);
		string strToSign = request.HttpMethod+"&" +EncodeValue("/") + "&" +EncodeValue(MakeQueryStr(queryData));
		string aks = request.AccessKeySecret + "&";
		const char *key = aks.c_str();
		unsigned char * mac = NULL;
		unsigned int mac_length = 0;
		HashHMAC("sha1", key, strlen(key), strToSign.c_str(), strToSign.length(), mac, mac_length);
		string signature = Base64Encode(reinterpret_cast<const unsigned char*>(mac), mac_length);
		delete [] mac;

		map<string,string> signQueryData;
		signQueryData["Signature"] = signature;
		EncodeParamValue(signQueryData);

		string signParam = MakeQueryStr(signQueryData);
		string finalUrl = api + MakeQueryStr(queryData) + "&" + signParam;

		std::cout<<"finalUrl--------------->>>"<<finalUrl<<std::endl;
		return this->sendRequest(request, finalUrl, postFields);
	}

	string ApiBase::sendRequest(const BaseRequest &request, const string &finalUrl, const string &postFields){
		CURL *curl;
		CURLcode res = CURLE_OK;
		string response("");
		struct curl_slist *headers = NULL;
		headers = curl_slist_append(headers, "aliyun-openapi-sdk-client: C++/1.0.0");
		curl = curl_easy_init();    // 初始化
		if (curl) {
			if( request.HttpMethod == "POST" ){
				//struct curl_httppost *formpost = NULL;
				//curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
			}
			curl_easy_setopt( curl, CURLOPT_CUSTOMREQUEST, request.HttpMethod.c_str());
			if( request.HttpMethod == "POST" ){
				curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postFields.c_str());
			}
			curl_easy_setopt( curl, CURLOPT_CONNECTTIMEOUT, 30L);
			//curl_easy_setopt(curl, CURLOPT_PROXY, "10.99.60.201:8080");// 代理
			curl_easy_setopt( curl, CURLOPT_HTTPHEADER, headers);// 改协议头
			curl_easy_setopt( curl, CURLOPT_URL, finalUrl.c_str() );

			//跳过服务器SSL验证，不使用CA证书
			curl_easy_setopt( curl, CURLOPT_SSL_VERIFYPEER, 0L);
			//验证服务器端发送的证书，默认是 2(高)，1（中），0（禁用）
			curl_easy_setopt( curl, CURLOPT_SSL_VERIFYHOST, 0L);

			curl_easy_setopt( curl, CURLOPT_WRITEFUNCTION, CurlCallBack);
			curl_easy_setopt( curl, CURLOPT_WRITEDATA, &response);

			res = curl_easy_perform(curl);// 执行

			if (res != CURLE_OK) {
				curl_slist_free_all(headers);
				curl_easy_cleanup(curl);
			}
		}
		curl_slist_free_all(headers);
		curl_easy_cleanup(curl);
		return response;
	}

	/**
	 * get the domain according the RegionId
	 */
	string ApiBase::getServiceDomain(const string &RegionId, const string &ProductName){
		map<string,string> hangzhou;
		map<string,string> shenzhen;
		map<string,string> qingdao;

		hangzhou["ros"] = "ros.aliyuncs.com";
		hangzhou["bss"] = "bss.aliyuncs.com";
		hangzhou["ecs"] = "ecs-cn-hangzhou.aliyuncs.com";
		hangzhou["oms"] = "oms.aliyuncs.com";
		hangzhou["rds"] = "rds.aliyuncs.com";
		hangzhou["slb"] = "slb-pop.aliyuncs.com";
		hangzhou["oss"] = "oss-cn-hangzhou.aliyuncs.com";
		hangzhou["ossadmin"] = "oss-admin.aliyuncs.com";
		hangzhou["sts"] = "sts.aliyuncs.com";
		hangzhou["yundun"] = "yundun-cn-hangzhou.aliyuncs.com";
		hangzhou["risk"] = "risk-cn-hangzhou.aliyuncs.com";
		hangzhou["drds"] = "drds.aliyuncs.com";
		hangzhou["m-kvstore"] = "m-kvstore.aliyuncs.com";
		hangzhou["ram"] = "ram.aliyuncs.com";
		hangzhou["cms"] = "metrics.aliyuncs.com";
		hangzhou["crm"] = "crm-cn-hangzhou.aliyuncs.com";
		hangzhou["ocs"] = "pop-ocs.aliyuncs.com";
		hangzhou["ots"] = "ots-pop.aliyuncs.com";
		hangzhou["dqs"] = "dqs.aliyuncs.com";
		hangzhou["location"] = "location.aliyuncs.com";
		hangzhou["ubsms"] = "ubsms.aliyuncs.com";
		hangzhou["drc"] = "drc.aliyuncs.com";
		hangzhou["ons"] = "ons.aliyuncs.com";
		hangzhou["aas"] = "aas.aliyuncs.com";
		hangzhou["ace"] = "ace.cn-hangzhou.aliyuncs.com";
		hangzhou["ubsms-inner"] = "ubsms-inner.aliyuncs.com";
		hangzhou["dts"] = "dts.aliyuncs.com";
		hangzhou["r-kvstore"] = "r-kvstore-cn-hangzhou.aliyuncs.com";
		hangzhou["pts"] = "pts.aliyuncs.com";
		hangzhou["alert"] = "alert.aliyuncs.com";
		hangzhou["push"] = "cloudpush.aliyuncs.com";
		hangzhou["emr"] = "emr.aliyuncs.com";
		hangzhou["cdn"] = "cdn.aliyuncs.com";

		shenzhen["ros"] = "ros.aliyuncs.com";
		shenzhen["batchcompute"] = "batchcompute.cn-shenzhen.aliyuncs.com";
		shenzhen["bss"] = "bss.aliyuncs.com";
		shenzhen["alert"] = "alert.aliyuncs.com";
		shenzhen["ecs"] = "ecs-cn-hangzhou.aliyuncs.com";
		shenzhen["oms"] = "oms.aliyuncs.com";
		shenzhen["rds"] = "rds.aliyuncs.com";
		shenzhen["slb"] = "slb-pop.aliyuncs.com";
		shenzhen["oss"] = "oss-cn-hangzhou.aliyuncs.com";
		shenzhen["ossadmin"] = "oss-admin.aliyuncs.com";
		shenzhen["sts"] = "sts.aliyuncs.com";
		shenzhen["yundun"] = "yundun-cn-hangzhou.aliyuncs.com";
		shenzhen["risk"] = "risk-cn-hangzhou.aliyuncs.com";
		shenzhen["drds"] = "drds.aliyuncs.com";
		shenzhen["m-kvstore"] = "m-kvstore.aliyuncs.com";
		shenzhen["ram"] = "ram.aliyuncs.com";
		shenzhen["cms"] = "metrics.aliyuncs.com";
		shenzhen["crm"] = "crm-cn-hangzhou.aliyuncs.com";
		shenzhen["ocs"] = "pop-ocs.aliyuncs.com";
		shenzhen["ots"] = "ots-pop.aliyuncs.com";
		shenzhen["dqs"] = "dqs.aliyuncs.com";
		shenzhen["location"] = "location.aliyuncs.com";
		shenzhen["ubsms"] = "ubsms.aliyuncs.com";
		shenzhen["drc"] = "drc.aliyuncs.com";
		shenzhen["ons"] = "ons.aliyuncs.com";
		shenzhen["aas"] = "aas.aliyuncs.com";
		shenzhen["ace"] = "ace.cn-hangzhou.aliyuncs.com";
		shenzhen["ubsms-inner"] = "ubsms-inner.aliyuncs.com";
		shenzhen["dts"] = "dts.aliyuncs.com";
		shenzhen["r-kvstore"] = "r-kvstore-cn-hangzhou.aliyuncs.com";
		shenzhen["pts"] = "pts.aliyuncs.com";
		shenzhen["alert"] = "alert.aliyuncs.com";
		shenzhen["push"] = "cloudpush.aliyuncs.com";
		shenzhen["emr"] = "emr.aliyuncs.com";
		shenzhen["cdn"] = "cdn.aliyuncs.com";

		qingdao["ros"] = "ros.aliyuncs.com";
		qingdao["batchcompute"] = "batchcompute.cn-qingdao.aliyuncs.com";
		qingdao["bss"] = "bss.aliyuncs.com";
		qingdao["ecs"] = "ecs-cn-hangzhou.aliyuncs.com";
		qingdao["oms"] = "oms.aliyuncs.com";
		qingdao["rds"] = "rds.aliyuncs.com";
		qingdao["slb"] = "slb-pop.aliyuncs.com";
		qingdao["oss"] = "oss-cn-hangzhou.aliyuncs.com";
		qingdao["ossadmin"] = "oss-admin.aliyuncs.com";
		qingdao["sts"] = "sts.aliyuncs.com";
		qingdao["yundun"] = "yundun-cn-hangzhou.aliyuncs.com";
		qingdao["risk"] = "risk-cn-hangzhou.aliyuncs.com";
		qingdao["drds"] = "drds.aliyuncs.com";
		qingdao["m-kvstore"] = "m-kvstore.aliyuncs.com";
		qingdao["ram"] = "ram.aliyuncs.com";
		qingdao["cms"] = "metrics.aliyuncs.com";
		qingdao["crm"] = "crm-cn-hangzhou.aliyuncs.com";
		qingdao["ocs"] = "pop-ocs.aliyuncs.com";
		qingdao["ots"] = "ots-pop.aliyuncs.com";
		qingdao["dqs"] = "dqs.aliyuncs.com";
		qingdao["location"] = "location.aliyuncs.com";
		qingdao["ubsms"] = "ubsms.aliyuncs.com";
		qingdao["drc"] = "drc.aliyuncs.com";
		qingdao["ons"] = "ons.aliyuncs.com";
		qingdao["aas"] = "aas.aliyuncs.com";
		qingdao["ace"] = "ace.cn-hangzhou.aliyuncs.com";
		qingdao["ubsms-inner"] = "ubsms-inner.aliyuncs.com";
		qingdao["dts"] = "dts.aliyuncs.com";
		qingdao["r-kvstore"] = "r-kvstore-cn-hangzhou.aliyuncs.com";
		qingdao["pts"] = "pts.aliyuncs.com";
		qingdao["alert"] = "alert.aliyuncs.com";
		qingdao["push"] = "cloudpush.aliyuncs.com";
		qingdao["emr"] = "emr.aliyuncs.com";
		qingdao["cdn"] = "cdn.aliyuncs.com";

		if(RegionId=="cn-hangzhou" && ProductName!=""){
			return hangzhou[ProductName];
		}
		if(RegionId=="cn-shenzhen" && ProductName!=""){
			return shenzhen[ProductName];
		}
		if(RegionId=="cn-qingdao" && ProductName!=""){
			return qingdao[ProductName];
		}
		return "";
	}
}
